#include "PlaylistClient.h"

using namespace std;

/*---------------------------------------------------------------------------------------
--	FUNCTION:	Playlistclient::PlaylistClient
--
--	DATE:			March 22, 2010
--
--	REVISIONS		(Date and Description):
--
--	DESIGNER:		Brad Paugh
--
--	PROGRAMMER:		Brad Paugh
--
--      INTERFACE:      PlaylistClient::PlaylistClient()
--
--	RETURNS:
--
--	NOTES:
--		Constructor for the playlist client that starts up WSA
---------------------------------------------------------------------------------------*/
PlaylistClient::PlaylistClient()
{
	WORD wVersionRequested = MAKEWORD(2,2);
	WSADATA WSAdata;
	WSAStartup(wVersionRequested, &WSAdata);
}

/*---------------------------------------------------------------------------------------
--	FUNCTION:	Playlistclient::connectToServer(string ip, int port)
--
--	DATE:			March 22, 2010
--
--	REVISIONS		(Date and Description):
--
--	DESIGNER:		Brad Paugh
--
--	PROGRAMMER:		Brad Paugh
--
--      INTERFACE:      void connectToServer(string ip, int port)
--				string ip - the ip address
--				int port - port to connect to
--
--	RETURNS:		void	
--
--	NOTES:
--		Connects to a server and starts the thread to read playlist info
---------------------------------------------------------------------------------------*/
void PlaylistClient::connectToServer(string ip, int port)
{
	sock.Create("TCP");
	sock.Connect(ip, port);
	CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)threadStart, this, 0, NULL);
}

/*---------------------------------------------------------------------------------------
--	FUNCTION:	Playlistclient::close ()
--
--	DATE:			March 22, 2010
--
--	REVISIONS		(Date and Description):
--
--	DESIGNER:		Eric Rebeiro
--
--	PROGRAMMER:		Eric Rebeiro
--
--	RETURNS:		void	
--
--	NOTES:
--		Method to terminate server
---------------------------------------------------------------------------------------*/
void PlaylistClient::close ()
{
}

/*---------------------------------------------------------------------------------------
--	FUNCTION:	Playlistclient::threadStart(void* param)
--
--	DATE:			March 22, 2010
--
--	REVISIONS		(Date and Description):
--
--	DESIGNER:		Brad Paugh
--
--	PROGRAMMER:		Brad Paugh
--
--      INTERFACE:      void threadStart(void* param)
--
--	RETURNS:		void	
--
--	NOTES:
--		A member function cannot be passed into CreateThread so we need to use this static
--		function to start the thread.
---------------------------------------------------------------------------------------*/
void PlaylistClient::threadStart(void* param)
{
	((PlaylistClient*)param)->receiveThread();
}

/*---------------------------------------------------------------------------------------
--	FUNCTION:	Playlistclient::receiveThread
--
--	DATE:			March 22, 2010
--
--	REVISIONS		(Date and Description):
--
--	DESIGNER:		Brad Paugh
--
--	PROGRAMMER:		Brad Paugh
--
--      INTERFACE:      void receiveThread()
--
--	RETURNS:		void	
--
--	NOTES:
--		thread to receive the current playlist from the server
---------------------------------------------------------------------------------------*/
void PlaylistClient::receiveThread()
{
	/*todo: integration: this should probably signal the GUI to read the playlist
	class whenever it completes the read*/
	OVERLAPPED overlapped;
	string buffer;
	int bytesReceived;

	if ((overlapped.hEvent = WSACreateEvent()) == WSA_INVALID_EVENT)
	{
		cout << "event error: " << WSAGetLastError();
		exit(1);
	}
	while(1)
	{
		bytesReceived = sock.Recv(buffer, PLAYLIST_SIZE, &overlapped);
		storePlaylist(buffer);
	}
}

/*---------------------------------------------------------------------------------------
--	FUNCTION:	Playlistclient::storePlaylist
--
--	DATE:			March 22, 2010
--
--	REVISIONS		(Date and Description):
--
--	DESIGNER:		Brad Paugh
--
--	PROGRAMMER:		Brad Paugh
--
--      INTERFACE:      void storePlaylist(string buffer)
--                              string buffer - the unmodifed buffer we have received from server
--
--	RETURNS:		void	
--
--	NOTES:
--		This function extracts the song/vote combinations from the string the server has
--		sent across and adds them into the client's playlist class
---------------------------------------------------------------------------------------*/
void PlaylistClient::storePlaylist(string buffer)
{
	char* cString;
	cString = (char*)malloc(buffer.length()+1);
	char* token;
	Song* s;
	int fname = 1;
	int first = 1;
	string nowPlaying;

	strcpy(cString, buffer.c_str());

	//reading tokens from the buffer (tokenized by ETX's)
	//first token is filename, second token is votes
	while ((token = strtok(cString, "\3")) != 0)
	{
		cString = 0;
		if (fname)
		{
			//first token is now playing song
			if (first)
			{
				nowPlaying = token;
				first = 0;
				continue;
			}
			string filename(token);
            s = new Song(filename, string(""));
			fname = 0;
		}
		else
		{
			int votes = atoi(token);
			s->setVotes(votes);
            playlist_.addSong(s);
			fname = 1;
		}
	}
	if (nowPlaying == "0")
		playlist_.setPlaying(new Song(" ", " "));
	else
		playlist_.setPlaying(playlist_.getSong(nowPlaying));
	
}

/*---------------------------------------------------------------------------------------
--	FUNCTION:	Playlistclient::outputPlaylist
--
--	DATE:			March 22, 2010
--
--	REVISIONS		(Date and Description):
--
--	DESIGNER:		Brad Paugh
--
--	PROGRAMMER:		Brad Paugh
--
--      INTERFACE:      string outputPlaylist()
--
--	RETURNS:		string
--
--	NOTES:
--		Outputs playlist string (for testing purposes)
---------------------------------------------------------------------------------------*/
std::string PlaylistClient::outputPlaylist()
{
	return playlist_.parseToString();
}

/*---------------------------------------------------------------------------------------
--	FUNCTION:	Playlistclient::sendFile
--
--	DATE:			March 22, 2010
--
--	REVISIONS		(Date and Description):
--
--	DESIGNER:		Brad Paugh
--
--	PROGRAMMER:		Brad Paugh
--
--      INTERFACE:      void sendFile(string path)
--                              string path - the path of the file that you wish to send
--
--	RETURNS:		void	
--
--	NOTES:
--		This function sends the file specified in path to the server.
---------------------------------------------------------------------------------------*/
void PlaylistClient::sendFile(string path)
{
	//parse the filename from the path
	this->path = path;
	filename = extractFilename(path);

        if (!isRunning())
            startRunning();
        else
            GlobalError::warning("Sorry, you are already uploading a file.");
}

/*---------------------------------------------------------------------------------------
--	FUNCTION:	Playlistclient::run ()
--
--	DATE:			March 22, 2010
--
--	REVISIONS		(Date and Description):
--
--	DESIGNER:		Eric Rebeiro
--
--	PROGRAMMER:		Eric Rebeiro
--
--	RETURNS:		void	
--
--	NOTES:
--		Method to run server
---------------------------------------------------------------------------------------*/
void PlaylistClient::run()
{
    unsigned long fileSize;
    char * cBuffer;
    cBuffer = (char *) malloc(DATA_SIZE);
    ifstream ifs(path.c_str(), ios_base::app | ios_base::in | ios_base::binary);
    ostringstream oss;

    if(!ifs)
        GlobalError::warning("Can't upload selected file.");

    ifs.seekg(0, ios::end);
    fileSize = ifs.tellg();
    ifs.seekg(0, ios::beg);

    uploadProgress = 0;
    notifyAll(UploadStarted);

    oss << "\x12" << filename;

    //send inital packet (DC1Filename)
    sock.Send(oss.str(), oss.str().length());

    while (1)
    {
        ifs.read(cBuffer, DATA_SIZE);
        int bytesRead = ifs.gcount();
        sock.Send(cBuffer, bytesRead);

        uploadProgress = (((double)ifs.tellg()) / ((double)fileSize)) * 100;
        notifyAll(UploadProgressChanged);

        if (ifs.eof())
            break;
    }

    //send terminating packet
    memset(cBuffer, '0', DATA_SIZE);
    sock.Send(cBuffer, DATA_SIZE);
    ifs.close();

    notifyAll(UploadFinished);
}

/*---------------------------------------------------------------------------------------
--	FUNCTION:	Playlistclient::extractFilename
--
--	DATE:			March 22, 2010
--
--	REVISIONS		(Date and Description):
--
--	DESIGNER:		Brad Paugh
--
--	PROGRAMMER:		Brad Paugh
--
--      INTERFACE:      string extractFilename(string path)
--                              string path - the path to extract filename from
--
--	RETURNS:		void	
--
--	NOTES:
--		This function extracts a filename from a path.
--
--		ex: path = "C:\files\test.wav"
--			returns "test.wav"
---------------------------------------------------------------------------------------*/
string PlaylistClient::extractFilename(string path)
{
        unsigned int position;

	//find the last occurance of backslash
	position = path.rfind("\\");

        if (position != string::npos)
	{
		//get everything after final backslash (filename)
                return path.substr(position+1);
	}
	return path;
}

/*---------------------------------------------------------------------------------------
--	FUNCTION:	Playlistclient::sendVote
--
--	DATE:			March 22, 2010
--
--	REVISIONS		(Date and Description):
--
--	DESIGNER:		Brad Paugh
--
--	PROGRAMMER:		Brad Paugh
--
--      INTERFACE:      void sendVote(string filename)
--                              string filename - the filename of the file on the server to vote for
--
--	RETURNS:		void	
--
--	NOTES:
--		This function sends a vote to the server
---------------------------------------------------------------------------------------*/
void PlaylistClient::sendVote(string filename)
{
	ostringstream oss;
	oss << "\x11" << filename;
	sock.Send(oss.str(), oss.str().length());
}
